package org.ykhl.sdk.appserver;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.ykhl.mq.commons.BaseMessage;
import org.ykhl.mq.commons.BaseMessagePojoImpl;
import org.ykhl.mq.commons.ConnectionException;
import org.ykhl.mq.commons.receiver.MessageListener;

import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Created by Zhangkefei on 2016/1/14.
 */
public class MessageQueue {

    private final String authId;
    private String serverUrl;
    private Boolean useSsl;
    private volatile boolean running = false;

    private WebTarget requestTarget, responseTarget;

    public MessageQueue(String authId, String serverUrl) {
        this.authId = authId;
        this.serverUrl = serverUrl;
    }

    /**
     * 设置MessageQueue连接的服务器地址.
     *
     * @param serverAddress
     */
    public void setServerAddress(String serverAddress){
        serverUrl = serverAddress;
    }

    /**
     * 设置是否使用加密及认证模式进行传输。
     *
     * @param useSsl
     */
    public void setUseSsl(Boolean useSsl) {
        this.useSsl = useSsl;
    }

    /**
     * 查看MessageQueue当前是否正在运行
     *
     * @return true if running, false otherwise
     */
    public boolean isRunning(){
        return running;
    }

    /**
     * 用于启动MessageQueue的方法, 开始使用前需要调用
     *
     * @throws ConnectionException
     */
    public void start() throws ConnectionException {
        if (running) return;

        Objects.requireNonNull(serverUrl, "serverUrl can't be null");

        ClientConfig config = new ClientConfig();
        config.property(ClientProperties.CONNECT_TIMEOUT, 30000)
                .property(ClientProperties.READ_TIMEOUT, 60000);

        WebTarget target = ClientBuilder.newClient(config).target(serverUrl);
        requestTarget = target.path("request");
        responseTarget = target.path("response");
        running = true;

    }

    /**
     * 用于停止MessageQueue的方法.
     *
     * @throws ConnectionException
     */
    public void stop() throws ConnectionException{
        if (!running) return;

        running = false;
    }

    /**
     * 设置推送消息的消息监听器.
     *
     * @param listener
     */
    public void setListener(MessageListener listener){
        // TODO
    }

    /**
     * 向平台发送医疗信息查询请求
     *
     * @param fid 请求的服务ID
     * @param requestBody 请求体字符串
     * @param deviceSign 请求来源的终端设备的特征码
     * @return 用于后续接受响应消息的requestId
     * @throws ConnectionException
     */
    public String sendRequest(String fid, String version, String requestBody,
                                                  String deviceSign, String ruleName)
            throws ConnectionException {

        Form form = new Form();
        form.param("authId", authId);
        form.param("fid", fid);
        form.param("version", version);
        form.param("content", requestBody);
        form.param("deviceSign", deviceSign);
        form.param("ruleName", ruleName);

        try {
            return requestTarget.request(MediaType.APPLICATION_JSON).post(
                    Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE), String.class);
        } catch (Exception e) {
            throw new ConnectionException(e);
        }
    }

    public BaseMessage poll(String requestId, long timeout, TimeUnit timeUnit)
            throws ConnectionException {

        Form form = new Form();
        form.param("authId", authId);
        form.param("requestId", requestId);

        if (timeout > 0 && timeUnit != null) {
            form.param("timeout", Long.toString(timeout));
            form.param("timeUnit", timeUnit.toString());
        }

        try {
            Response response = responseTarget.request(MediaType.APPLICATION_JSON).post(
                    Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
            Response.StatusType statusType = response.getStatusInfo();

            if (statusType.equals(Response.Status.OK)) {
                return response.readEntity(BaseMessagePojoImpl.class);
            } else if (statusType.equals(Response.Status.REQUEST_TIMEOUT)) {
                return null;
            } else {
                throw new ConnectionException(statusType.getReasonPhrase());
            }

        } catch (Exception e) {
            throw new ConnectionException(e);
        }
    }

    public BaseMessage poll(String requestId) throws ConnectionException {
        return poll(requestId, -1, null);
    }

    private void checkRunning() {
        if (isRunning()) return;

        throw new IllegalStateException("MessageQueue is not running");
    }
}
